package com.mjk.common.core.jdbc.service.plus.provider.abstractor;


import com.mjk.common.base.model.BaseEntity;
import com.mjk.common.core.jdbc.annotation.ArcSharding;
import com.mjk.common.core.jdbc.annotation.Filed;
import com.mjk.common.core.jdbc.ibatis.typehandler.handler.*;
import com.mjk.common.core.jdbc.service.plus.constns.BeeTypeEntity;
import com.mjk.common.core.jdbc.service.plus.provider.BeeDataSourceType;
import com.mjk.common.core.jdbc.service.plus.provider.interfaces.IBeeProvider;
import com.mjk.common.core.jdbc.service.plus.provider.interfaces.IBeeTypeMapping;
import com.mjk.common.core.jdbc.util.TableUtils;
import com.mjk.common.core.jdbc.util.provider.SqlProvider;
import com.mjk.common.tools.logger.BizLogger;
import com.mjk.common.tools.springextend.BeeSpringBean;
import com.mjk.common.util.ClassUtil;
import org.apache.ibatis.type.JdbcType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * postgresql
 *
 * @author Administrator
 *
 */
public abstract class AbstractPostgreSqlProvider  implements IBeeProvider, IBeeTypeMapping {
    private Set<BeeTypeEntity> allMapping = new HashSet<>(Arrays.asList(
            new BeeTypeEntity(JdbcType.BIT, "BIT", Boolean.class.getName(), "4", 0, new BooleanHandler()),
            new BeeTypeEntity(JdbcType.TINYINT, "TINYINT", Byte.class.getName(), "4", 1, new ByteHandler()),
            new BeeTypeEntity(JdbcType.SMALLINT, "SMALLINT", Short.class.getName(), "4", 0, new ShortHandler()),
            new BeeTypeEntity(JdbcType.INTEGER, "INT", Integer.class.getName(), "11", 0, new IntegerHandler()),
            new BeeTypeEntity(JdbcType.BIGINT, "BIGINT", Long.class.getName(), "20", 1, new LongHandler()),
            new BeeTypeEntity(JdbcType.FLOAT, "FLOAT", Float.class.getName(), "1", 0, new FloatHandler()),
            new BeeTypeEntity(JdbcType.REAL, "FLOAT", Float.class.getName(), "0", 0, new FloatHandler()),
            new BeeTypeEntity(JdbcType.DOUBLE, "DOUBLE", Double.class.getName(), "10,2", 1, new DoubleHandler()),
            new BeeTypeEntity(JdbcType.DECIMAL, "DECIMAL", java.math.BigDecimal.class.getName(), "0", 0, new BigDecimalHandler()),
            new BeeTypeEntity(JdbcType.CHAR, "CHAR", String.class.getName(), "1", 0, new StringHandler()),
            new BeeTypeEntity(JdbcType.VARCHAR, "VARCHAR", String.class.getName(), "255", 1, new StringHandler()),
            new BeeTypeEntity(JdbcType.LONGVARCHAR, "LONGVARCHAR", String.class.getName(), "255", 0, new StringHandler()),
            new BeeTypeEntity(JdbcType.TIMESTAMP, "TIMESTAMP", Date.class.getName(), "6", 0, new DateHandler()),
            new BeeTypeEntity(JdbcType.TIME, "TIME", java.sql.Time.class.getName(), "0", 0, new DateHandler()),
            new BeeTypeEntity(JdbcType.BINARY, "BINARY", Byte.class.getName(), "1", 0, new ByteHandler()),
            new BeeTypeEntity(JdbcType.TIMESTAMP, "TIMESTAMP", LocalDateTime.class.getName(), "6", 0, new LocalDateTimeHandler()),
            new BeeTypeEntity(JdbcType.DATE, "DATE", LocalDate.class.getName(), "0", 0, new LocalDateHandler()),
            new BeeTypeEntity(JdbcType.TIME, "TIME", LocalTime.class.getName(), "1", 0, new LocalTimeHandler()),
            new BeeTypeEntity(JdbcType.VARBINARY, "TINYBLOB", Byte.class.getName(), "4", 0, new ByteHandler()),
            new BeeTypeEntity(JdbcType.LONGVARBINARY, "BLOB", Byte.class.getName(), "4", 0, new ByteHandler()),
            new BeeTypeEntity(JdbcType.BLOB, "BLOB", java.sql.Blob.class.getName(), "0", 1, new BlobHandler()),
            new BeeTypeEntity(JdbcType.CLOB, "CLOB", java.sql.Clob.class.getName(), "0", 1, new ClobHandler()),
            new BeeTypeEntity(JdbcType.OTHER, "VARCHAR", String.class.getName(), "255", 0, new StringHandler())
    ));
    ;;
    private Map<String, BeeTypeEntity> javaMapping;

    public Set<BeeTypeEntity> getMapping() {
        javaMapping = initJavaTypeMap(allMapping);
        return allMapping;
    }

    @Override
    public Map<JdbcType, BeeTypeEntity> getJdbcMap() {
        return allMapping.stream().collect(Collectors.toMap(BeeTypeEntity::getJdbcType, obj -> obj, (key1, key2) -> key1));
    }

    @Override
    public Map<String, BeeTypeEntity> getJavaMap() {
        return allMapping.stream().collect(Collectors.toMap(BeeTypeEntity::getJavaType, obj -> obj, (key1, key2) -> key1));
	}

	@Override
	public String getCreateTable(BaseEntity entiry) {

		return "CREATE TABLE %s ( " + buildFiledSql(entiry, BeeDataSourceType.POSTGRESQL_WRAP) + " ";
	}
	@Override
	public String buildFiledSql(BaseEntity o, BeeDataSourceType type) {
        List<Field> fields = SqlProvider.getValidTableFiled(o);
		StringBuilder sb = new StringBuilder();
		StringBuilder commentBuffer = new StringBuilder();
		for (Field f : fields) {
			createSQL(sb, f,type,false);
			Filed filed = f.getAnnotation(Filed.class);
			if(null!=filed) {
				commentBuffer.append("COMMENT ON COLUMN ").append(TableUtils.getTableName(o)).append(".").append(f.getName()).append(" IS '").append(filed.comment()).append("';");
			}
		}
		if (sb.toString().endsWith(",")) {
			String tmp = sb.substring(0, sb.toString().length() - 1);
			return tmp +");"+ commentBuffer;
		}
		return sb +");"+ commentBuffer;
	}

	@Override
	public String getFiledLenght(String clazz, String length) {
		clazz = ClassUtil.getSimpleName(clazz);
		if (clazz.equals(Integer.class.getName())) {
			return "";
		}
		return getFiledLenght(clazz, length);
	}


	@Override
	public String getAutoIncrement(boolean primary) {
		if (primary) {
			return " SERIAL PRIMARY KEY ";
		}
		return "";
	}

	@Override
	public String getComment(String comment) {
		return ",";
	}

    @Override
	public String getTabName(ArcSharding arc) {
		return arc.table();
	}
	@Override
	public String getTableStruct(String tabName) {
		return "select * from " + tabName + " LIMIT 0";
	}
	@Override
	public String getTableStructDetail(ArcSharding arc) {
		String sql = " SELECT table_name,COLUMN_NAME,DATA_TYPE,col_description(b.oid, a.ordinal_position) COLUMN_COMMENT FROM information_schema.columns a,pg_class b WHERE  a.table_name=b.relname" ;
		if (arc.table() != null) {
			sql = sql + " where table_name = '" + arc.table() + "';";
		}
		return sql;
	}

	@Override
	public void initPramaryIncrement(BaseEntity entity) {
		String tableName = TableUtils.getTableName(entity);
		JdbcTemplate jdbcTemplate = BeeSpringBean.getBean(JdbcTemplate.class);
		String seqSql = "CREATE SEQUENCE "+tableName+"_seq"+"\r\n"+
				"INCREMENT BY 1"+ "\r\n"+
				"START WITH 1"+"\r\n"+
				"NO MINVALUE"+"\r\n"+
				"NO MAXVALUE"+"\r\n"+
				"CACHE 1";
		try{
			Objects.requireNonNull(jdbcTemplate).execute(seqSql);
		}catch(Exception e){
			BizLogger.error(e);
		}
        String pramary = SqlProvider.getPramaryKey(entity);
		if(ObjectUtils.isEmpty(pramary)) {
			return;
		}
		String tiggertSql ="alter table "+tableName+" alter column "+pramary+" set default nextval('"+tableName+"_seq')";
		try{
			Objects.requireNonNull(jdbcTemplate).execute(tiggertSql);
		}catch(Exception e){
			BizLogger.error(e);
		}
	}
}
